package vnc;
import java.awt.*;
import java.awt.event.*;

import java.io.*;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


import javax.swing.*;
import javax.swing.border.CompoundBorder;

import vnc.JDStatisticsTakerLoader;
import vnc.stat.JDStatisticsTaker;

import vnc.ui.JDContinuousStatFrame;
import vnc.ui.JDCumlativeStatFrame;
import vnc.ui.JDStatFrame;

import jpcap.*;
import jpcap.packet.IPPacket;
import jpcap.packet.Packet;

public class VncFrame extends JFrame {
	/**
	 * 
	 */
	
	public static int packSize=0;
	private static final long serialVersionUID = 1L;

	// visual network analyzer title height
	private int titleHeight;
	
	// the location of vncFrame
	private static Point point = new Point();
	
	// top and bottom height of application
	private int headerHeight;
	private int bottomHeight;
	
	// size of application
	private int appWidth;
	private int appHeight;
	
	// root Panel
	JPanel rootPane;
	
	// layered panels
	JPanel topPane;
	JPanel middlePane;
	JPanel bottomPane;
	
	// Nic card select Panel
	NicSelectPanel stageAPane;
	
	// packet Analyzing Panel
	PacketAnalyzePanel stageBPane;

	// how many packets are captured?
	JLabel statusLabel;
	
	// close, minimize window buttons
	JToolBar windowButtons;
	JButton close, minimize;
	
	// real toolBar.. start, stop etc...
	JToolBar toolBar;
	JButton play, stop, packet, graph_1, graph_2;
	
	// Jpcap
	
	public static long MAX_PACKETS_HOLD=10000;
	
	List<Packet> packets = new ArrayList<Packet>();

	boolean isLiveCapture;
	boolean isSaved = false;
	
	public JpcapCaptor jpcap = null;

	NetworkInterface[] devices;

	
	private ImageIcon getImageIcon(String path){
		return new ImageIcon(this.getClass().getResource(path));
	}
	
	private ImageIcon scaleImageIcon(ImageIcon icon, int width, int height){
		
		Image img = icon.getImage();
		//BufferedImage bi = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
		//Graphics g = bi.createGraphics();
		//g.drawImage(img, 0, 0, width, height, null, null);
		//icon = new ImageIcon(bi);
		
		Image newimg = img.getScaledInstance(width, height, java.awt.Image.SCALE_SMOOTH);
		
		icon = new ImageIcon(newimg);
		
		return icon;
	}
	
	private void removeButtonBorder(JButton jb){
		jb.setBorderPainted(false);
		jb.setContentAreaFilled(false);
		jb.setDefaultCapable(false);
		jb.setFocusPainted(false);
	}
	
	protected void addWindowButtons(JToolBar toolBar){
		//int buttonWidth = 30;
		//int buttonHeight = 30;
		
		final VncFrame vncframe = this;
		
		minimize = new JButton(getImageIcon("/images/minimize.png"));
		minimize.setPressedIcon(getImageIcon("/images/minimize_pressed.png"));
		minimize.setRolloverIcon(getImageIcon("/images/minimize_rollover.png"));
		removeButtonBorder(minimize);
		minimize.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				vncframe.setState(ICONIFIED);
			}
		});
		toolBar.add(minimize);
		
		close = new JButton(getImageIcon("/images/close.png"));
		close.setPressedIcon(getImageIcon("/images/close_pressed.png"));
		close.setRolloverIcon(getImageIcon("/images/close_rollover.png"));
		removeButtonBorder(close);
		close.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				System.exit(0);
			}
		});
		toolBar.add(close);
	}
	
	protected void stageA(){
		// stage 1... it goes in middlePane
		stageAPane = new NicSelectPanel();
		
		stageAPane.setBackground(middlePane.getBackground());
		
		stageAPane.setPreferredSize(new Dimension(appWidth, appHeight - headerHeight - bottomHeight));
		stageAPane.setMinimumSize(new Dimension(appWidth, appHeight - headerHeight - bottomHeight));
		stageAPane.setMaximumSize(new Dimension(appWidth, appHeight - headerHeight - bottomHeight));
		stageAPane.init(appWidth, appHeight - headerHeight - bottomHeight);
		
		stageAPane.next.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent evt){
				
				middlePane.remove(stageAPane);
				
				stageB();
				
				middlePane.revalidate();
				middlePane.repaint();
			}
		});
		
		middlePane.setLayout(new GridLayout(0,1));
		middlePane.add(stageAPane);
	}
	
	protected void stageB(){
		
		stageBPane = new PacketAnalyzePanel(packets, appWidth, appHeight - headerHeight - bottomHeight);
		
		stageBPane.setBackground(middlePane.getBackground());
		
		stageBPane.setPreferredSize(new Dimension(appWidth, appHeight - headerHeight - bottomHeight));
		stageBPane.setMinimumSize(new Dimension(appWidth, appHeight - headerHeight - bottomHeight));
		stageBPane.setMaximumSize(new Dimension(appWidth, appHeight - headerHeight - bottomHeight));
		
		middlePane.setLayout(new GridLayout(0,1));
		middlePane.add(stageBPane);
		
		capturePacketsFromDevice();

	}
	
	protected void addToolBarButtons(JToolBar toolBar){
		
		int buttonWidth = 32;
		int buttonHeight = 32;
		
		play = new JButton(scaleImageIcon(getImageIcon("/images/play.png"), buttonWidth, buttonHeight));
		play.setPressedIcon(scaleImageIcon(getImageIcon("/images/play_pressed.png"), buttonWidth, buttonHeight));
		play.setRolloverIcon(scaleImageIcon(getImageIcon("/images/play_rollover.png"), buttonWidth, buttonHeight));
		
		removeButtonBorder(play);
		
		play.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				middlePane.removeAll();
				stageA();
				middlePane.revalidate();
				middlePane.repaint();
			}
		});
		
		toolBar.add(play);
		
		stop = new JButton(scaleImageIcon(getImageIcon("/images/stop.png"), buttonWidth, buttonHeight));
		stop.setPressedIcon(scaleImageIcon(getImageIcon("/images/stop_pressed.png"), buttonWidth, buttonHeight));
		stop.setRolloverIcon(scaleImageIcon(getImageIcon("/images/stop_rollover.png"), buttonWidth, buttonHeight));
		removeButtonBorder(stop);
		
		stop.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				//middlePane.removeAll();
				
				stopCapture();
				
				//정지버튼누를때 어드레스 테이블 생성.
				stageBPane.mb.tableStart();
				//middlePane.revalidate();
				//middlePane.repaint();
			}
		});
		
		toolBar.add(stop);
		
		packet = new JButton(scaleImageIcon(getImageIcon("/images/packet.png"), buttonWidth, buttonHeight));
		packet.setPressedIcon(scaleImageIcon(getImageIcon("/images/packet_pressed.png"), buttonWidth, buttonHeight));
		packet.setRolloverIcon(scaleImageIcon(getImageIcon("/images/packet_rollover.png"), buttonWidth, buttonHeight));
		removeButtonBorder(packet);
		
		packet.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				middlePane.removeAll();
				
				middlePane.setLayout(new GridLayout(0,1));
				middlePane.add(stageBPane);
				
				middlePane.revalidate();
				middlePane.repaint();
			}
		});
		
		toolBar.add(packet);
		
		graph_1 = new JButton(scaleImageIcon(getImageIcon("/images/graph_1.png"), buttonWidth, buttonHeight));
		graph_1.setPressedIcon(scaleImageIcon(getImageIcon("/images/graph_1_pressed.png"), buttonWidth, buttonHeight));
		graph_1.setRolloverIcon(scaleImageIcon(getImageIcon("/images/graph_1_rollover.png"), buttonWidth, buttonHeight));
		removeButtonBorder(graph_1);
		
		graph_1.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				middlePane.removeAll();
				
				middlePane.setLayout(new GridLayout(0,2));
				middlePane.add(spanels.get(1));
				middlePane.add(spanels.get(2));
				middlePane.add(spanels.get(3));
				middlePane.add(spanels.get(0));
				
				spanels.get(1).setBorder(new CompoundBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.WHITE), BorderFactory.createLineBorder(new Color(178, 178, 178))));
				spanels.get(2).setBorder(new CompoundBorder(BorderFactory.createMatteBorder(2, 0, 2, 2, Color.WHITE), BorderFactory.createLineBorder(new Color(178, 178, 178))));
				spanels.get(3).setBorder(new CompoundBorder(BorderFactory.createMatteBorder(0, 2, 2, 2, Color.WHITE), BorderFactory.createLineBorder(new Color(178, 178, 178))));
				spanels.get(0).setBorder(new CompoundBorder(BorderFactory.createMatteBorder(0, 0, 2, 2, Color.WHITE), BorderFactory.createLineBorder(new Color(178, 178, 178))));
				
				middlePane.revalidate();
				middlePane.repaint();
			}
		});
		
		toolBar.add(graph_1);
		
		graph_2 = new JButton(scaleImageIcon(getImageIcon("/images/graph_2.png"), buttonWidth, buttonHeight));
		graph_2.setPressedIcon(scaleImageIcon(getImageIcon("/images/graph_2_pressed.png"), buttonWidth, buttonHeight));
		graph_2.setRolloverIcon(scaleImageIcon(getImageIcon("/images/graph_2_rollover.png"), buttonWidth, buttonHeight));
		removeButtonBorder(graph_2);
		
		graph_2.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				middlePane.removeAll();
				
				middlePane.setLayout(new GridLayout(0,2));
				middlePane.add(spanels.get(5));
				middlePane.add(spanels.get(6));
				middlePane.add(spanels.get(7));
				middlePane.add(spanels.get(4));
				
				spanels.get(5).setBorder(BorderFactory.createMatteBorder(3, 3, 3, 3, Color.WHITE));
				spanels.get(6).setBorder(BorderFactory.createMatteBorder(3, 0, 3, 3, Color.WHITE));
				spanels.get(7).setBorder(BorderFactory.createMatteBorder(0, 3, 3, 3, Color.WHITE));
				spanels.get(4).setBorder(BorderFactory.createMatteBorder(0, 0, 3, 3, Color.WHITE));
				
				middlePane.revalidate();
				middlePane.repaint();
			}
		});
		
		toolBar.add(graph_2);
		
	}
	
	public void init(){
		
		statusLabel = new JLabel("  todavia nada");
		
		titleHeight = 20;
		
		// top and bottom height of application
		headerHeight = 60;
		bottomHeight = 20;
		
		// size of application
		appWidth = 1024;
		appHeight = 600;
		
		rootPane = new JPanel();
		
		topPane = new JPanelHeader();
		middlePane = new JPanel();
		bottomPane = new JPanelBottom();
		
		// close, minimize
		windowButtons = new JToolBar();
		addWindowButtons(windowButtons);
		
		windowButtons.setFloatable(false);
		windowButtons.setBorderPainted(false);
		windowButtons.setOpaque(false);
		
		// real toolBar.. start, stop etc...
		toolBar = new JToolBar();
		addToolBarButtons(toolBar);
		
		toolBar.setFloatable(false);
		toolBar.setBorderPainted(false);
		toolBar.setOpaque(false);
		//toolBar.addSeparator();
		
		rootPane.setBorder(BorderFactory.createLineBorder(new Color(178, 178, 178)));
		
		rootPane.setBackground(Color.RED);
		middlePane.setBackground(Color.WHITE);
		
		rootPane.setLayout(new BoxLayout(rootPane, BoxLayout.Y_AXIS));
		
		rootPane.setSize(appWidth, appHeight);
		
		topPane.setPreferredSize(new Dimension(appWidth, headerHeight));
		topPane.setMinimumSize(new Dimension(appWidth, headerHeight));
		topPane.setMaximumSize(new Dimension(appWidth, headerHeight));
		
		middlePane.setPreferredSize(new Dimension(appWidth, appHeight - headerHeight - bottomHeight));
		middlePane.setMinimumSize(new Dimension(appWidth, appHeight - headerHeight -  bottomHeight));
		middlePane.setMaximumSize(new Dimension(appWidth, appHeight - headerHeight -  bottomHeight));
		
		bottomPane.setPreferredSize(new Dimension(appWidth, bottomHeight));
		bottomPane.setMinimumSize(new Dimension(appWidth, bottomHeight));
		bottomPane.setMaximumSize(new Dimension(appWidth, bottomHeight));
		
		//topPane.setSize(appWidth, headerHeight);
		//bottomPane.setSize(appWidth, 20);
		
		//rootPane.add(topPane, BorderLayout.NORTH);
		//rootPane.add(middlePane, BorderLayout.CENTER);
		//rootPane.add(bottomPane, BorderLayout.SOUTH);
		
		JLabel title = new JLabel("Visual Network Analyzer", JLabel.CENTER);
		
		//topPane.setLayout(new GridLayout(0,2));
		topPane.setLayout(null);
		middlePane.setLayout(new GridLayout(0,1));
		bottomPane.setLayout(new GridLayout(0,1));
		
		topPane.add(title);
		topPane.add(windowButtons);
		topPane.add(toolBar);
		
		/////////////move window...//////////////
		topPane.addMouseListener(new MouseAdapter(){
			public void mousePressed(MouseEvent e){
				point.x = e.getX();
				point.y = e.getY();
			}
		});
		final VncFrame vncframe = this;
		topPane.addMouseMotionListener(new MouseMotionAdapter(){
			public void mouseDragged(MouseEvent e){
				Point p = vncframe.getLocation();
				vncframe.setLocation(p.x + e.getX() - point.x, p.y + e.getY() - point.y);
			}
		});
		///////////////////////////
		
		title.setBounds(0, 0, appWidth, titleHeight);
		// for OSX
		windowButtons.setBounds(appWidth-57, 2, 52, 20);
		// for windows 7
		//windowButtons.setBounds(appWidth-57, 2, 50, 20);
		toolBar.setBounds(0, title.getHeight()-1, 44*5, headerHeight-title.getHeight());
		
		// first stage.. showing logo..
		middlePane.add(new JLabel(getImageIcon("/images/logo.png")));
		
		bottomPane.add(statusLabel);

		rootPane.add(topPane);
		rootPane.add(middlePane);
		rootPane.add(bottomPane);
				
		this.setLayout(new FlowLayout());
		
		this.setLocation(0, 0);
		this.setSize(appWidth, appHeight);
		
		this.setContentPane(rootPane);
	}
	
	public List<Packet> getPackets(){
		return packets;
	}
	
	
	List<JDStatFrame> spanels=new ArrayList<JDStatFrame>();
	
	public void addCumulativeStatFrame(JDStatisticsTaker taker) {
		spanels.add(JDCumlativeStatFrame.openPanel(packets,taker.newInstance()));
	}

	public void addContinuousStatFrame(JDStatisticsTaker taker) {
		spanels.add(JDContinuousStatFrame.openPanel(packets,taker.newInstance()));
	}
	
	public void addStatisitcs(){
		
		// in spanels LinkedList.. first three 0~2 ... continuousStat Panel
		// in spanels LinkedList.. second three 3~5 ... CumulativeStat Panel
		
		addContinuousStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(0));
		addContinuousStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(1));
		addContinuousStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(2));
		addContinuousStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(3));
		//addContinuousStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(4));
		
		addCumulativeStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(0));
		addCumulativeStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(1));
		addCumulativeStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(2));
		addCumulativeStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(3));
		//addCumulativeStatFrame(JDStatisticsTakerLoader.getStatisticsTakerAt(4));
	}
	
	public void capturePacketsFromDevice() {
		
		if(jpcap!=null)
			jpcap.close();
		
		if(!packets.isEmpty())
			clear();
		
		try {
			jpcap = JpcapCaptor.openDevice(stageAPane.getSelectedNicDevice(),1514,false,50);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		clear();
		
		if (jpcap != null) {
			
			isLiveCapture = true;
			
			
			disableCapture();

			startCaptureThread();
			
			// statistics !
			addStatisitcs();
			
		}
	}
	
	public void initToolBar(){
		play.setEnabled(true);
		stop.setEnabled(false);
		packet.setEnabled(false);
		graph_1.setEnabled(false);
		graph_2.setEnabled(false);
	}
	
	public void enableCapture(){
		play.setEnabled(true);
		stop.setEnabled(false);
		packet.setEnabled(true);
		graph_1.setEnabled(true);
		graph_2.setEnabled(true);
	}
	
	public void disableCapture(){
		play.setEnabled(false);
		stop.setEnabled(true);
		packet.setEnabled(true);
		graph_1.setEnabled(true);
		graph_2.setEnabled(true);
	}
	
	private void clear(){
		// Removes all of the elements from this list (optional operation). 
		//This list will be empty after this call returns (unless it throws an exception)
		for(int i=0;i<spanels.size();i++)
			((JDStatFrame)spanels.get(i)).clear();
		
		stageBPane.clear();
		
		packets.clear();
	}


	public void stopCapture() {
		stopCaptureThread();
	}


	public void closeAllWindows(){
	
	}

	private Thread captureThread;
	
	private void startCaptureThread() {
		
		if (captureThread != null) return;
		
		captureThread = new Thread(new Runnable(){
			public void run() {
				while (captureThread != null) {
					
					if (jpcap.processPacket(1, handler) == 0 && !isLiveCapture){
						
						stopCaptureThread();
					}
					Thread.yield();
				}

				jpcap.breakLoop();
				
				enableCapture();
			}
		});
		
		captureThread.setPriority(Thread.MIN_PRIORITY);
		
		
		startUpdating();
		
		for(int i=0;i<spanels.size();i++){
			((JDStatFrame)spanels.get(i)).startUpdating();
		}
		
		captureThread.start();
	}

	void stopCaptureThread() {
		captureThread = null;
		
		for(int i=0;i<spanels.size();i++){
			((JDStatFrame)spanels.get(i)).stopUpdating();
		}

		stopUpdating();
		//box stop adjustAllBoxesLocation and Size

	}
	
	public void startUpdating(){
		vncBottomUpdater.setRepeats(true);
		vncBottomUpdater.start();
	}
	
	public void stopUpdating(){
		vncBottomUpdater.stop();
		vncBottomUpdater.setRepeats(false);
		vncBottomUpdater.start();
	}
		
	private ExecutorService exe=Executors.newFixedThreadPool(10);
	public static final Map<InetAddress,String> hostnameCache=new HashMap<InetAddress, String>();
	
	int i=0;
	
	private PacketReceiver handler = new PacketReceiver()
	{
	
		public void receivePacket(final Packet packet) {
			
			packets.add(packet);
			packSize++;
			
			// need to solve out..
			while (packets.size() > MAX_PACKETS_HOLD) {
				
				packets.remove(0);
				//stageBPane.removeBox(0);
				
			}
			
			// it is useless.. but just in case anyway
			if (!spanels.isEmpty()) {
				for (int i = 0; i < spanels.size(); i++)
					((JDStatFrame)spanels.get(i)).addPacket(packet);
			}

			isSaved = false;
			
			if(packet instanceof IPPacket){
				
				exe.execute(new Runnable(){
					public void run() {
						IPPacket ip=(IPPacket)packet;
						if(!hostnameCache.containsKey(ip.src_ip))
							{hostnameCache.put(ip.src_ip,ip.src_ip.getHostName());}
						if(!hostnameCache.containsKey(ip.dst_ip))
							{hostnameCache.put(ip.dst_ip,ip.dst_ip.getHostName());}
					}
				});
			}
		}
	};
	
	javax.swing.Timer vncBottomUpdater = new javax.swing.Timer(500,new ActionListener(){
		
		public void actionPerformed(ActionEvent evt){
			
			statusLabel.setText("  Total "+packets.size()+" packets are held.");

			repaint();
		}
	});
	
	VncFrame(){
		
		this.init();
		
		initToolBar();
		this.setUndecorated(true);
		this.setVisible(true);
	}

}
